package pratice.aop;

import com.alibaba.fastjson.JSON;
import framework.util.aopLog.Log;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.aspectj.lang.reflect.SourceLocation;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;

/**
 * @author 吴宇亮 on 2019/6/22 8:55
 */
@Aspect
public class AopImpl {

//    @Around("@annotation(framework.util.aopLog.Log)")
    public void recordByAnnotation(ProceedingJoinPoint pjp){
        Signature sig = pjp.getSignature(); //获取要准备执行的方法的签名
        Object target = pjp.getTarget(); //获取要真正被调用的对象
        Object[] args = pjp.getArgs(); //获取入参

        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("recordRuntime切点只能用于方法");
        }
        MethodSignature methodSignature = (MethodSignature) sig;

        try {
            LocalDateTime now = LocalDateTime.now();
            System.out.println("当前时间：" + now.format(DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss")));
            Class<?> clazz = target.getClass();
            System.out.println("被调用的类：" + clazz.getName());
            Method currentMethod = clazz.getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
            System.out.println("准备要执行的方法：" + currentMethod.getName());
            Class<?>[] parameterTypes = currentMethod.getParameterTypes();
            System.out.println("方法参数类型：" + JSON.toJSONString(parameterTypes));

            Log annotation = currentMethod.getAnnotation(Log.class);
            System.out.println("funcName: " + annotation.funcName() + ", modelName" + annotation.modelName());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        //fastjson的实现：sysout是调用方法的toString，而fastJson是真正可以看出来类的属性，估计它的实现逻辑是获取该对象的所有变量，然后看下有没有get方法，有就输出，没有就不输出（假想正确）
        System.out.println("方法入参：" + JSON.toJSONString(args));

        long begin = System.nanoTime();
        try {
            //执行目标方法
            Object proceed = (0 != args.length) ?  proceed = pjp.proceed(args) : pjp.proceed();
            System.out.println("方法返回值：" + JSON.toJSONString(proceed));

        } catch (Throwable e) {
            //如果发生了异常
//            e.printStackTrace();
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            System.out.println(sw.toString());
        }
        long end = System.nanoTime();
        System.out.println("PerformanceMonitorUserService: 耗时" + TimeUnit.MILLISECONDS.convert((end - begin), TimeUnit.NANOSECONDS) + "毫秒");

        System.out.println();
        //没有抛出异常就记录


        System.out.println();
        System.out.println("----------------------------------");
    }


    /**
     * 记录方法的执行时间
     * @param pjp
     */
    //切面表达式
    //@Around("execution(* doSport(..))")
    public void recordRuntime(ProceedingJoinPoint pjp) {
        Signature sig = pjp.getSignature(); //获取要准备执行的方法的签名
        Object target = pjp.getTarget(); //获取要真正被调用的对象
        Object[] args = pjp.getArgs(); //获取入参

        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("recordRuntime切点只能用于方法");
        }
        MethodSignature methodSignature = (MethodSignature) sig;

        try {
            Class<?> clazz = target.getClass();
            System.out.println("被调用的类：" + clazz.getName());
            Method currentMethod = clazz.getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
            System.out.println("准备要执行的方法：" + currentMethod.getName());
            Class<?>[] parameterTypes = currentMethod.getParameterTypes();
            System.out.println("方法参数类型：" + JSON.toJSONString(parameterTypes));
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        //fastjson的实现：sysout是调用方法的toString，而fastJson是真正可以看出来类的属性，估计它的实现逻辑是获取该对象的所有变量，然后看下有没有get方法，有就输出，没有就不输出（假想正确）
        System.out.println("方法入参：" + JSON.toJSONString(args));

        long begin = System.nanoTime();
        try {
            //执行目标方法
            Object proceed = (0 != args.length) ?  proceed = pjp.proceed(args) : pjp.proceed();
            System.out.println("方法返回值：" + JSON.toJSONString(proceed));

        } catch (Throwable e) {
            e.printStackTrace();
            //如果发生了异常
        }
        long end = System.nanoTime();
        System.out.println("PerformanceMonitorUserService: 耗时" + TimeUnit.MILLISECONDS.convert((end - begin), TimeUnit.NANOSECONDS) + "毫秒");

        System.out.println();
        //没有抛出异常就记录


        System.out.println();
        System.out.println("----------------------------------");
    }
}
